﻿using System.Diagnostics.Contracts;
using System.Linq;

namespace Library.Collections
{
    using Library.Collections.Generic;

    public interface IEdgeFrom : IEdgeFrom<INodeIncoming> { }

    public interface IEdgeTo : IEdgeTo<INodeOutgoing> { }

    public interface IEdge : IEdge<INode> { }

    public interface INodeIncoming : INodeIncoming<IEdgeFrom> { }

    public interface INodeOutgoing : INodeOutgoing<IEdgeTo> { }

    public interface INode : INode<IEdge> { }

    public interface IGraphIncomingReadOnly : IGraphReadOnly<INodeIncoming, IEdgeFrom> { }

    public interface IGraphOutgoingReadOnly : IGraphReadOnly<INodeOutgoing, IEdgeTo> { }

    public interface IGraphReadOnly : IGraphReadOnly<INode, IEdge> { }

    public interface IGraphIncoming : IGraph<INodeIncoming, IEdgeFrom> { }

    public interface IGraphOutgoing : IGraph<INodeOutgoing, IEdgeTo> { }

    public interface IGraph : IGraph<INode, IEdge> { }

    public interface IGraphRootIncoming : IGraphRoot<INodeIncoming, IEdgeFrom> { }

    public interface IGraphRootOutgoing : IGraphRoot<INodeOutgoing, IEdgeTo> { }

    public interface IGraphRoot : IGraphRoot<INode, IEdge> { }

}

namespace Library.Collections.Generic
{
    public interface IEdgeFrom<out TNode>
    {
        [Pure]
        TNode From { get; }
    }

    public interface IEdgeTo<out TNode>
    {
        [Pure]
        TNode To { get; }
    }

    public interface IEdge<out TNode> : IEdgeFrom<TNode>, IEdgeTo<TNode> { }



    public interface INodeIncoming<out TEdge>
    {
        [Pure]
        IQueryable<TEdge> Incoming { get; }
    }

    public interface INodeOutgoing<out TEdge>
    {
        [Pure]
        IQueryable<TEdge> Outgoing { get; }
    }

    public interface INode<out TEdge> : INodeIncoming<TEdge>, INodeOutgoing<TEdge> { }



    public interface IGraphReadOnly<out TNode, out TEdge> : IQueryable<TEdge> { }

    public interface IGraph<out TNode, out TEdge> : IGraphReadOnly<TNode, TEdge> { }



    public interface IGraphRoot<out TNode>
    {
        [Pure]
        TNode Root { get; }
    }

    public interface IGraphRootReadOnly<out TNode, out TEdge> : IGraphRoot<TNode>, IGraphReadOnly<TNode, TEdge> { }

    public interface IGraphRoot<out TNode, out TEdge> : IGraphRootReadOnly<TNode, TEdge>, IGraph<TNode, TEdge> { }
}